#pragma once
#include <iostream>
#include <cstdarg>

namespace zxf
{
    enum zxf_err
    {
        USE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR,
        ACCEPT_ERR,
        READ_ERR,
        WRITE_ERR,
        CONNECT_ERR,
        WAAITPID_ERR
    };
}

// 定义日志等级
#define DEBUG 0   // bug
#define NORMAL 1  // 正常
#define WARNING 2 // 警告
#define ERROR 3   // 错误
#define FATAL 4   // 致命错误

// 我们传入得错误信息接口是 :
//  logMessage(日志等级, foemat...);

// 打印/或者输出到文件得信息格式是 :
//  [日志等级] [时间戳/时间] [pid] [error_messge]
// 例如:
//  [WARNING] [2023-05-11 18:09:08] [123] [创建socket失败]

// 这是一个 可变参数得函数接口
// 我们先学习C语言和c++得可变参数怎么写
// 学习一下一套函数

// #include <stdio.h>
// int printf(const char *format, ...);
// int fprintf(FILE *stream, const char *format, ...);
// int sprintf(char *str, const char *format, ...);
// int snprintf(char *str, size_t size, const char *format, ...);

// #include <stdarg.h>
// int vprintf(const char *format, va_list ap);
// int vfprintf(FILE *stream, const char *format, va_list ap);
// int vsprintf(char *str, const char *format, va_list ap);
// int vsnprintf(char *str, size_t size, const char *format, va_list ap);

// 调用方式
// logMessage(DEBUG, "hello %f, %d, %c", 3.14, 10, 'C');
std::string level_str(int level)
{
    switch (level)
    {
    case DEBUG:
        return "DEBUG";
    case NORMAL:
        return "NORMAL";
    case WARNING:
        return "WARNING";
    case ERROR:
        return "ERROR";
    case FATAL:
        return "FATAL";
    default:
        return nullptr;
    }
}

// 时间戳转化为时间 毫秒级
std::string Stamp2Time(const time_t timestamp)
{
    // int ms = timestamp % 1000;                // 取毫秒
    // time_t tick = (time_t)(timestamp / 1000); // 转换时间
    // struct tm tm;
    // char s[40];
    // tm = *localtime(&tick);
    // strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", &tm);
    // std::string str(s);
    // str = str + " " + std::to_string(ms);
    // return str;

    struct tm *timeinfo;
    int year, month, day, hour, minute, second;

    timeinfo = localtime(&timestamp);
    year = timeinfo->tm_year + 1900;
    month = timeinfo->tm_mon + 1;
    day = timeinfo->tm_mday;
    hour = timeinfo->tm_hour;
    minute = timeinfo->tm_min;
    second = timeinfo->tm_sec;

    char buf[64];
    bzero(buf, 64);
    sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
    return std::string(buf);
}

void logMessage(int level, const char *format, ...)
{
    // 先做出:[日志等级] [时间戳/时间] [pid]
    // char logprefix[NUM];
    // snprintf(logprefix, sizeof(logprefix), "[%s][%ld][pid: %d]",
    //          level_str(level), (long int)time(nullptr), getpid());
    std::string pro = "";
    pro += "[";
    pro += level_str(level);
    pro += "]";

    // // 时间表示做了简化(用时间戳)
    // pro += "[";
    // pro += std::to_string((long int)time(nullptr));
    // pro += "]";
    // 也可以直接具体时间表示(不用时间戳)
    time_t curtime = time(NULL);
    pro += "[";
    pro += Stamp2Time(curtime);
    pro += "]";

    pro += "[";
    pro += std::to_string(getpid());
    pro += "]";
    // 基本信息完成;

    char logcontent[1024];
    va_list arg;
    va_start(arg, format);
    // 直接获取出格式化出的文本,不用自己去分析format,自己拼接
    vsnprintf(logcontent, sizeof(logcontent), format, arg);

    // 打印日志信息
    // std::cout << pro << logcontent << std::endl;

    // 输出到文件
    FILE *err = fopen("err.log", "a");
    FILE *log = fopen("log.log", "a");

    if (err != nullptr && log != nullptr)
    {
        FILE *curr = nullptr;
        if (level == DEBUG || level == NORMAL || level == WARNING)
            curr = log;
        if (level == ERROR || level == FATAL)
            curr = err;
        if (curr)
            fprintf(curr, "%s %s\n", pro.c_str(), logcontent);
    }
    fclose(log);
    fclose(err);
    //注意一定要关闭文件,不然OS不刷新
}
